#include "Utilities.h"

_UTILITIES_BEGIN_

vector<string> Split(const string& line, char delim)
{
	string curStr;
	vector<string> tokens;
	char curChar;

	for(int i = 0; i < (int)line.size(); i++)
	{
		curChar = line[i];
		if(curChar == delim)
		{
			tokens.push_back(curStr);
			curStr.clear();
		}
		else
		{
			curStr += curChar;
		}
	}
	if(!curStr.empty())
		tokens.push_back(curStr);
	return tokens;
}

const double MAX_DOUBLE = 999.99;
const double PI = 3.1415927;

/************************************************************************/
/*	Calculate the distance of two points.                               */
/*	Parameters:															*/
/*		x0 - the x coordinate of the first point						*/
/*		y0 - the y coordinate of the first point						*/
/*		y1 - the x coordinate of the second point						*/
/*		y2 - the y coordinate of the second point						*/
/*	Return:																*/
/*		the value of the distance.										*/
/************************************************************************/
double calculateEuclideanDistance(double x0, double y0, double x1, double y1)
{
	double distance = sqrt(pow(x0 - x1, 2) + pow(y0 - y1, 2));
	return distance;
}

/************************************************************************/
/*	Calculate the parameters of the line by the two given points.		*/
/*	y=kx+b, return the pair of k(first) and b(second).                  */
/*	Parameters:															*/
/*		x0 - the x coordinate of the first point						*/
/*		y0 - the y coordinate of the first point						*/
/*		y1 - the x coordinate of the second point						*/
/*		y2 - the y coordinate of the second point						*/
/*	Return:																*/
/*		the value of the parameters in the form of pair, the first		*/
/*		value is k and the second is b.									*/
/************************************************************************/
std::pair<double, double> calculateLineParameters(double x0, double y0, double x1, double y1)
{
	pair<double, double> para;

	if (x0 != x1)	// line is not parallel to the y coordinate
	{
		para.first = (y0 - y1) / (x0 - x1);
	}
	else
	{
		para.first = MAX_DOUBLE;
		para.second = 0;
	}
	if (y0 != y1)
	{
		para.second = y1 - para.first * x1;
	}
	else
	{
		para.second = y0;
	}
	return para;
}

/************************************************************************/
/*	Calculate the l-perpendicular value between a point of a partition	*/
/*	to another partition.												*/
/*	Parameters:															*/
/*		x0			- the x coordinate of the point						*/
/*		y0			- the y coordinate of the point						*/
/*		lineParam	- the parameters of Lj								*/
/*	Return:																*/
/*		the value of the L-perpendicular, that is the distance from the */
/*		point to the line with the parameter linePara					*/
/************************************************************************/
double calculateLperpendicular(double x0, double y0, std::pair<double, double> linePara)
{
	double lPer = abs(-linePara.first * x0 + y0 - linePara.second) / sqrt(1 + linePara.first * linePara.first);
	return lPer;
}

/************************************************************************/
/*	Calculate the d-perpendicular value between two partitions.			*/
/*	From L1 to L2, lp1 and lp2 are the distances from two points of L1  */
/*	to L2.																*/
/*	Parameters:															*/
/*		lp1 - the value of l-perpendiculer from the first point			*/
/*		lp2 - the value of l-perpendicular from the second point		*/
/*	Return:																*/
/*		the value of d-perpendicular									*/
/************************************************************************/
double calculatePerpendicularDistance(double lp1, double lp2)
{
	double PD = (lp1 * lp1 + lp2 * lp2) / (lp1 + lp2);
	return PD;
}

double calculatePerpendicularDistanceEx(double x0, double y0, double x1, double y1, double x2, double y2, double x3, double y3)
{
	pair<double, double> Lj = calculateLineParameters(x2, y2, x3, y3);
	double lp1 = calculateLperpendicular(x0, y0, Lj);
	double lp2 = calculateLperpendicular(x1, y1, Lj);
	double PD = calculatePerpendicularDistance(lp1, lp2);

	return PD;
}

/************************************************************************/
/*	Calculate the D-theta value from Li to Lj.		                    */
/*	Parameters:															*/
/*		x0 - the x coordinate of the first point of Lj					*/
/*		y0 - the y coordinate of the first point of Lj					*/
/*		x1 - the x coordinate of the second point of Lj					*/
/*		y1 - the y coordinate of the second point of Lj					*/
/*		Li - the parameters of one line									*/
/*		Lj - the parameters of another line								*/
/*	Return:																*/
/*		the value of angle distance										*/
/************************************************************************/
double calculateAngleDistance(double x0, double y0, double x1, double y1, std::pair<double, double> Li, std::pair<double, double> Lj)
{
	double dX = x0 - x1;
	double dY = y0 - y1;
	double aDist = sqrt(dX * dX + dY * dY);

	if (Li.first == Lj.first || Li.first == -Lj.first)	//	if two partitions are parallel or perpendicular
	{
		return aDist;
	}
	else	
	{
		double degree = atan(Li.first) - atan(Lj.first);
		aDist *= sin(degree);
	}

	if (Li.first * Lj.first < 0)	// if the angle of two partitions are larger than 90 degree
	{
		aDist = PI / 2 - aDist;
	}
	return abs(aDist);
}

double calculateAngleDistanceEx(double x0, double y0, double x1, double y1, double x2, double y2, double x3, double y3)
{
	pair<double, double> Li = calculateLineParameters(x0, y0, x1, y1);
	pair<double, double> Lj = calculateLineParameters(x2, y2, x3, y3);

	double angleDistance = calculateAngleDistance(x0, y0, x1, y1, Li, Lj);

	return angleDistance;
}

/************************************************************************/
/*	Calculate the D-parallel value between Li and Lj.                   */
/*	Parameters:															*/
/*		x0 - the x coordinate of the first point of Li					*/
/*		y0 - the y coordinate of the first point of Li					*/
/*		x1 - the x coordinate of the second point of Li					*/
/*		y1 - the y coordinate of the second point of Li					*/
/*		Lj - the parameters of Lj										*/
/*		x2 - the x coordinate of the first point of Lj					*/
/*		y2 - the y coordinate of the first point of Lj					*/
/*		x3 - the x coordinate of the second point of Lj					*/
/*		y3 - the y coordinate of the second point of Lj					*/
/*	Return:																*/
/*		the value of the parallel distance								*/
/************************************************************************/
double calculateParallelDistance(double x0, double y0, double x1, double y1, std::pair<double, double> Lj, double x2, double y2, double x3, double y3)
{
	//cout << "x0, y0, Lj.first, Lj.second:" << x0 << "," << y0 << "," << Lj.first << "," << Lj.second << endl;

	double a0, b0, a1, b1;

	if (Lj.first == 0)
	{
		a0 = x0;
		b0 = y2;
		a1 = x1;
		b1 = y3;
	}
	else
	{
		a0 = (Lj.first * x0 + y0 - Lj.second) / 2 * Lj.first;
		b0 = (y0 + Lj.first * x0 + Lj.second) / 2;
		a1 = (Lj.first * x1 + y1 - Lj.second) / 2 * Lj.first;
		b1 = (y1 + Lj.first * x1 + Lj.second) / 2;
	}

	double dist1 = sqrt((a0 - x2) * (a0 - x2) + (b0 - y2) * (b0 - y2));
	double dist2 = sqrt((a1 - x3) * (a1 - x3) + (b1 - y3) * (b1 - y3));

	if (dist1 > dist2)
	{
		return dist2;
	}
	else
		return dist1;

}

double calculateParallelDistanceEx(double x0, double y0, double x1, double y1, double x2, double y2, double x3, double y3)
{
	pair<double, double> Lj = calculateLineParameters(x2, y2, x3, y3);

	double parallelDistance = calculateParallelDistance(x0, y0, x1, y1, Lj, x2, y2, x3, y3);

	return parallelDistance;
}

/************************************************************************/
/*	Calculate the Distance between two partition.                       */
/*	Parameters:															*/
/*		x0		- the x coordinate of the first point of Li				*/
/*		y0		- the y coordinate of the first point of Li				*/
/*		x1		- the x coordinate of the second point of Li			*/
/*		y1		- the y coordinate of the second point of Li			*/
/*		x2		- the x coordinate of the first point of Lj				*/
/*		y2		- the y coordinate of the first point of Lj				*/
/*		x3		- the x coordinate of the second point of Lj			*/
/*		y3		- the y coordinate of the second point of Lj			*/
/*		Wper	- the weight for the perpendicular distance				*/
/*		Wpar	- the weight for the parallel distance					*/
/*		Wthe	- the weight for the theta distance						*/
/*	Return:																*/
/*		the value of the distance										*/
/************************************************************************/
double calculateDistance(double x0, double y0, double x1, double y1, double x2, double y2, double x3, double y3, double Wper, double Wpar, double Wthe)
{
	double distance = Wper * calculatePerpendicularDistanceEx(x0, y0, x1, y1, x2, y2, x3, y3) 
		+ Wpar * calculateParallelDistanceEx(x0, y0, x1, y1, x2, y2, x3, y3)
		+ Wthe * calculateAngleDistanceEx(x0, y0, x1, y1, x2, y2, x3, y3);

	return distance;
}

_UTILITIES_END_